unit scLogger;

interface

uses SysUtils, Classes, Dialogs;

type
  TWriteLogProc = procedure(const FileName, Msg: string);

{
 Writes a Msg to file with file name AppFileName and .log extension
}
procedure AppWriteLog(const Msg: string);

{
 Writes a log message in the critical section through WriteLogProc or DefaultWriteLog procedure
}
procedure WriteLog(const FileName: TFileName; const Msg: string);

{
 Writes a log message in file
}
procedure DefaultWriteLog(const FileName: TFileName; const Msg: string);

var
  AppFileName   : string = '';        //Variable used in Log procedures. Default is ParamStr(0)
  WriteLogProc  : TWriteLogProc = nil;//When assigned, called by WriteLog procedure
  AppLogTimeout : Integer       = 0;  //Timeout for waiting for logfile to be opened

implementation
uses Windows;

var
  FLogLock: TRTLCriticalSection;

procedure AppWriteLog(const Msg: string);
begin
  WriteLog(AppFileName, Msg);
end;

procedure WriteLog(const FileName: TFileName; const Msg: string);
var
  Tmp: string;
begin
  Tmp := DateTimeToStr(Now) + ' ' + Msg;
  EnterCriticalSection(FLogLock);
  try
    if Assigned(WriteLogProc)
      then WriteLogProc(FileName, Tmp)
      else DefaultWriteLog(FileName, Tmp);
  finally
    LeaveCriticalSection(FLogLock);
  end
end;

procedure DefaultWriteLog(const FileName: TFileName; const Msg: string);
var
  Mode : Word;
begin
  try
    if FileExists(FileName) then Mode := fmOpenReadWrite else Mode := fmCreate;
    with TFileStream.Create(FileName, Mode) do
    try
      Position := Size;
      WriteBuffer(PChar(Msg + #13#10)^, Length(Msg) + 2);
    finally
      Free();
    end;
  except
    // 'eat' any exception - logging is operation with lowwwwwest priority
  end;
end;

initialization
  InitializeCriticalSection(FLogLock);
  AppFileName := ChangeFileExt(ParamStr(0), '.log');

finalization
  DeleteCriticalSection(FLogLock);
end.
